﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Murry.DataStore.MemoryDB
{
    /// <summary>
    /// Base class for all Memory entities.
    /// </summary>
    [Serializable]
    public abstract class MemoryPersist : IPersist, ICloneable
    {
        /// <summary>
        /// Standard constructor.
        /// </summary>
        /// <param name="database">Memory Database Instance.</param>
        /// <exception cref="ArgumentNullException">If database is null.</exception>
        protected MemoryPersist(MemoryDatabase database)
        {
            if (database == null)
            {
                throw new ArgumentNullException("database");
            }

            Database = database;
        }

        /// <summary>
        /// Database instance.
        /// </summary>
        [NonSerialized] 
        protected MemoryDatabase Database;

        /// <summary>
        /// Unique Identifier.
        /// </summary>
        public string Id { get; protected internal set; }

        /// <summary>
        /// Add to DataStore.
        /// </summary>
        /// <exception cref="InvalidOperationException">If Add fails.</exception>
        public virtual void Add()
        {
            lock (Database)
            {
                Database.Add(this);
            }
        }

        /// <summary>
        /// Update in DataStore.
        /// </summary>
        /// <exception cref="InvalidOperationException">If Update fails.</exception>
        public virtual void Update()
        {
            lock (Database)
            {
                Database.Update(this);
            }
        }

        /// <summary>
        /// Delete from DataStore.
        /// </summary>
        /// <exception cref="InvalidOperationException">If Delete fails.</exception>
        public virtual void Delete()
        {
            lock (Database)
            {
                Database.Delete(this);
            }
        }

        /// <summary>
        /// Clone this object
        /// </summary>
        /// <returns>Clone.</returns>
        public virtual object Clone()
        {
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using (stream)
            {
                formatter.Serialize(stream, this);
                stream.Seek(0, SeekOrigin.Begin);
                var clone = (MemoryPersist) formatter.Deserialize(stream);

                clone.Database = Database;

                return clone;
            }
        }
    }
}
